package org.zoomdev.zoom.aop.modules;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zoomdev.zoom.aop.AopFactory;
import org.zoomdev.zoom.aop.AspectFactory;
import org.zoomdev.zoom.aop.MethodInvokerFactory;
import org.zoomdev.zoom.aop.ProxyFactory;
import org.zoomdev.zoom.aop.annotations.NoEnhance;
import org.zoomdev.zoom.aop.factory.AopInterceptorFactory;
import org.zoomdev.zoom.aop.factory.ConstructorFactory;
import org.zoomdev.zoom.aop.factory.GetterFactory;
import org.zoomdev.zoom.aop.factory.SetterFactory;
import org.zoomdev.zoom.aop.impl.AsmProxyFactory;
import org.zoomdev.zoom.aop.impl.AspectFactoryImpl;
import org.zoomdev.zoom.common.filter.ClassFilter;
import org.zoomdev.zoom.common.res.ResScanner;
import org.zoomdev.zoom.ioc.Ioc;
import org.zoomdev.zoom.ioc.IocEnhancer;
import org.zoomdev.zoom.ioc.annotations.IocBean;
import org.zoomdev.zoom.ioc.annotations.Module;
import org.zoomdev.zoom.ioc.annotations.ModuleInit;
import org.zoomdev.zoom.ioc.impl.factories.ModuleIocFactory;

@Module()
@NoEnhance
public final class CoreAopModule implements ModuleIocFactory.ModuleInitialize {

    public static final String NAME = "AOP";

//    @IocBean()
//    public AopFactory getAopFactory(ClassPool classPool, MethodInvokerFactory factory) {
//        return new JavassistAopFactory(classPool,factory);
//    }

//    @IocBean
//    public MethodParameterNamesGetter getClassInfo(ClassPool classPool) {
//        return new JavassistMethodParameterNamesGetter(classPool);
//    }


    @IocBean
    public AspectFactory createAopIocProxy(AopFactory aopFactory, Ioc ioc) {
        return new AspectFactoryImpl(aopFactory, ioc);
    }

    @ModuleInit
    public void config(AopFactory aopFactory, Ioc ioc) {
        aopFactory.addFactory(new AopInterceptorFactory(ioc), 0);
    }

    @Override
    public void initialize(Ioc ioc) {

        AopFactory aop = ioc.fetch(AopFactory.class);
        aop.addBlackList(clazz -> clazz.isAnnotationPresent(Module.class));
        ProxyFactory proxyFactory = ioc.fetch(ProxyFactory.class);
        ResScanner scanner = ioc.fetch(ResScanner.class);
        ioc.addFactory(new IocProxyFactory(proxyFactory));
        ioc.setEnhancer((IocEnhancer) aop);

        ModuleIocFactory moduleIocFactory = ioc.fetch(ModuleIocFactory.class);
        moduleIocFactory.execute(ioc, value -> ArrayUtils.contains(value.getParameterTypes(), AopFactory.class));

        AsmBeanCreator.create(moduleIocFactory, ioc, scanner, aop);

    }

    @IocBean()
    public AopFactory getAopFactory() {
        //return new JavassistAopFactory(ClassPool.getDefault(), MethodInvokerFactory.FACTORY);
        return new AsmAopFactory();
    }

    @IocBean
    public ProxyFactory getProxyFactory() {
        return new AsmProxyFactory();
    }


    @IocBean
    public ConstructorFactory getConstructorFactory() {
        return ConstructorFactory.FACTORY;
    }

    @IocBean
    public SetterFactory getSetterFactory() {
        return SetterFactory.FACTORY;
    }

    @IocBean
    public GetterFactory getGetterFactory() {
        return GetterFactory.FACTORY;
    }


    @IocBean
    public MethodInvokerFactory getFactory() {
        return MethodInvokerFactory.FACTORY;
    }


}
